﻿using System;
using System.Text;
using System.Threading;

namespace Eflong.Utility
{
    public class ReadErrorThread
    {
        private System.Threading.Thread m_Thread;
        private System.Diagnostics.Process m_Process;
        private String m_Error;
        private bool m_HasExisted;
        private object m_LockObj = new object( );

        public String Error
        {
            get
            {
                return m_Error;
            }
        }

        public bool HasExisted
        {
            get
            {
                lock ( m_LockObj )
                {
                    return m_HasExisted;
                }
            }

            set
            {
                lock ( m_LockObj )
                {
                    m_HasExisted = value;
                }
            }
        }

        private void ReadError( )
        {
            StringBuilder strError = new StringBuilder( );
            while ( !m_Process.HasExited )
            {
                strError.Append( m_Process.StandardError.ReadLine( ) );
            }

            strError.Append( m_Process.StandardError.ReadToEnd( ) );

            m_Error = strError.ToString( );
            HasExisted = true;
        }

        public ReadErrorThread( System.Diagnostics.Process p )
        {
            HasExisted = false;
            m_Error = string.Empty;
            m_Process = p;
            m_Thread = new Thread( new ThreadStart( ReadError ) );
            m_Thread.Start( );
        }
    }

    public class ProcessEventArgs : EventArgs
    {
        private string _msg;

        public ProcessEventArgs( string msg )
        {
            this._msg = msg;
        }

        public string PrecessMsg( )
        {
            return this._msg;
        }
    }

    public delegate void ProcessCompletedHandler( object sender , ProcessEventArgs e );

    public delegate void ProcessProgressHandler( object sender , ProcessEventArgs e );

    public class RunProcess
    {
        private String m_Error;
        private String m_Output;

        public String Error
        {
            get
            {
                return m_Error;
            }
        }

        public String Output
        {
            get
            {
                return m_Output;
            }
        }

        public bool HasError
        {
            get
            {
                return m_Error != "" && m_Error != null;
            }
        }

        public event ProcessProgressHandler ProcessProgress;

        public event ProcessCompletedHandler ProcessCompleted;

        public void Run( String fileName , String para )
        {
            StringBuilder outputStr = new StringBuilder( );

            try
            {
                //disable the error report dialog.
                //reference: http://www.devcow.com/blogs/adnrg/archive/2006/07/14/Disable-Error-Reporting-Dialog-for-your-application-with-the-registry.aspx
                Microsoft.Win32.RegistryKey key;
                key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( @"software\microsoft\PCHealth\ErrorReporting\" , true );
                int doReport = ( int )key.GetValue( "DoReport" );

                if ( doReport != 0 )
                {
                    key.SetValue( "DoReport" , 0 );
                }

                int showUI = ( int )key.GetValue( "ShowUI" );
                if ( showUI != 0 )
                {
                    key.SetValue( "ShowUI" , 0 );
                }
            }
            catch
            {
            }

            m_Error = string.Empty;
            m_Output = string.Empty;
            try
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process( );

                p.StartInfo.FileName = fileName;
                p.StartInfo.Arguments = para;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = true;

                p.Start( );

                ReadErrorThread readErrorThread = new ReadErrorThread( p );

                while ( !p.HasExited )
                {
                    string msg = p.StandardOutput.ReadLine( );
                    if ( this.ProcessProgress != null )
                    {
                        this.ProcessProgress( this , new ProcessEventArgs( msg ) );
                    }
                    outputStr.Append( msg + "\r\n" );
                    Thread.Sleep( 1 );
                }

                outputStr.Append( p.StandardOutput.ReadToEnd( ) );

                while ( !readErrorThread.HasExisted )
                {
                    Thread.Sleep( 1 );
                }

                m_Error = readErrorThread.Error;
                m_Output = outputStr.ToString( );

                p.Close( );
                if ( this.ProcessCompleted != null )
                {
                    this.ProcessCompleted( this , new ProcessEventArgs( m_Output ) );
                }
            }
            catch ( Exception e )
            {
                m_Error = e.Message;
            }
        }
    }
}